// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

namespace Admin.NET.Core.Service;

/// <summary>
/// 跨租户权限管理服务 🧩
/// </summary>
[ApiDescriptionSettings(Order = 295)]
public class SysCrossTenantService : IDynamicApiController, ITransient
{
    private readonly UserManager _userManager;
    private readonly SqlSugarRepository<SysUserCrossTenant> _crossTenantRep;
    private readonly SqlSugarRepository<SysTenant> _tenantRep;
    private readonly SqlSugarRepository<SysUser> _userRep;
    private readonly SysCacheService _sysCacheService;

    public SysCrossTenantService(
        UserManager userManager,
        SqlSugarRepository<SysUserCrossTenant> crossTenantRep,
        SqlSugarRepository<SysTenant> tenantRep,
        SqlSugarRepository<SysUser> userRep,
        SysCacheService sysCacheService)
    {
        _userManager = userManager;
        _crossTenantRep = crossTenantRep;
        _tenantRep = tenantRep;
        _userRep = userRep;
        _sysCacheService = sysCacheService;
    }

    /// <summary>
    /// 获取用户跨租户权限列表 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取用户跨租户权限列表")]
    public virtual async Task<SqlSugarPagedList<CrossTenantOutput>> Page(PageCrossTenantInput input)
    {
        return await _crossTenantRep.AsQueryable()
            .LeftJoin<SysUser>((ct, u) => ct.UserId == u.Id)
            .LeftJoin<SysTenant>((ct, u, t) => ct.TargetTenantId == t.Id)
            .LeftJoin<SysUser>((ct, u, t, gu) => ct.GrantedByUserId == gu.Id)
            .WhereIF(input.UserId > 0, (ct, u, t, gu) => ct.UserId == input.UserId)
            .WhereIF(input.TargetTenantId > 0, (ct, u, t, gu) => ct.TargetTenantId == input.TargetTenantId)
            .WhereIF(input.Permission.HasValue, (ct, u, t, gu) => ct.Permission == input.Permission)
            .WhereIF(input.IsActive.HasValue, (ct, u, t, gu) => ct.IsActive == input.IsActive)
            .WhereIF(!string.IsNullOrWhiteSpace(input.UserAccount), (ct, u, t, gu) => u.Account.Contains(input.UserAccount))
            .WhereIF(!string.IsNullOrWhiteSpace(input.UserRealName), (ct, u, t, gu) => u.RealName.Contains(input.UserRealName))
            .OrderBy((ct, u, t, gu) => new { ct.CreateTime }, OrderByType.Desc)
            .Select((ct, u, t, gu) => new CrossTenantOutput
            {
                Id = ct.Id,
                UserId = ct.UserId,
                UserAccount = u.Account,
                UserRealName = u.RealName,
                TargetTenantId = ct.TargetTenantId,
                TargetTenantName = t.Title,
                Permission = ct.Permission,
                ExpireTime = ct.ExpireTime,
                IsActive = ct.IsActive,
                Remark = ct.Remark,
                GrantedByUserId = ct.GrantedByUserId,
                GrantedByUserName = gu.RealName,
                CreateTime = ct.CreateTime
            })
            .ToPagedListAsync(input.Page, input.PageSize);
    }

    /// <summary>
    /// 授予跨租户权限 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [UnitOfWork]
    [ApiDescriptionSettings(Name = "Grant"), HttpPost]
    [DisplayName("授予跨租户权限")]
    public virtual async Task<long> GrantCrossTenantPermission(GrantCrossTenantInput input)
    {
        // 验证目标用户是否存在
        var targetUser = await _userRep.GetByIdAsync(input.UserId);
        if (targetUser == null) throw Oops.Oh("目标用户不存在");

        // 验证目标租户是否存在
        var targetTenant = await _tenantRep.GetByIdAsync(input.TargetTenantId);
        if (targetTenant == null) throw Oops.Oh("目标租户不存在");

        // 验证用户不能给自己的租户授权
        if (targetUser.TenantId == input.TargetTenantId) throw Oops.Oh("不能给用户授予自己租户的权限");

        // 检查是否已存在相同权限
        var existingPermission = await _crossTenantRep.GetFirstAsync(ct => 
            ct.UserId == input.UserId && ct.TargetTenantId == input.TargetTenantId);

        if (existingPermission != null)
        {
            // 更新现有权限
            existingPermission.Permission = input.Permission;
            existingPermission.ExpireTime = input.ExpireTime;
            existingPermission.IsActive = input.IsActive;
            existingPermission.Remark = input.Remark;
            existingPermission.GrantedByUserId = _userManager.UserId;
            await _crossTenantRep.UpdateAsync(existingPermission);
            
            // 清除缓存
            ClearUserCrossTenantCache(input.UserId);
            return existingPermission.Id;
        }
        else
        {
            // 创建新权限
            var crossTenantPermission = input.Adapt<SysUserCrossTenant>();
            crossTenantPermission.GrantedByUserId = _userManager.UserId;
            var result = await _crossTenantRep.InsertReturnEntityAsync(crossTenantPermission);
            
            // 清除缓存
            ClearUserCrossTenantCache(input.UserId);
            return result.Id;
        }
    }

    /// <summary>
    /// 撤销跨租户权限 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [UnitOfWork]
    [ApiDescriptionSettings(Name = "Revoke"), HttpPost]
    [DisplayName("撤销跨租户权限")]
    public virtual async Task RevokeCrossTenantPermission(RevokeCrossTenantInput input)
    {
        var permission = await _crossTenantRep.GetByIdAsync(input.Id);
        if (permission == null) throw Oops.Oh("权限记录不存在");

        await _crossTenantRep.DeleteAsync(permission);
        
        // 清除缓存
        ClearUserCrossTenantCache(permission.UserId);
    }

    /// <summary>
    /// 获取用户可访问的租户列表 🔖
    /// </summary>
    /// <param name="userId">用户ID，为空则获取当前用户</param>
    /// <returns></returns>
    [DisplayName("获取用户可访问的租户列表")]
    public virtual async Task<List<AccessibleTenantOutput>> GetAccessibleTenants(long? userId = null)
    {
        var targetUserId = userId ?? _userManager.UserId;
        
        // 获取用户信息
        var user = await _userRep.GetByIdAsync(targetUserId);
        if (user == null) return new List<AccessibleTenantOutput>();

        var result = new List<AccessibleTenantOutput>();

        // 添加用户自己的租户
        if (user.TenantId.HasValue)
        {
            var ownTenant = await _tenantRep.GetByIdAsync(user.TenantId.Value);
            if (ownTenant != null)
            {
                result.Add(new AccessibleTenantOutput
                {
                    TenantId = ownTenant.Id,
                    TenantName = ownTenant.Title,
                    Permission = CrossTenantPermissionEnum.FullAccess,
                    IsOwnTenant = true
                });
            }
        }

        // 获取跨租户权限
        var crossTenantPermissions = await GetValidCrossTenantPermissions(targetUserId);
        
        foreach (var permission in crossTenantPermissions)
        {
            var tenant = await _tenantRep.GetByIdAsync(permission.TargetTenantId);
            if (tenant != null)
            {
                result.Add(new AccessibleTenantOutput
                {
                    TenantId = tenant.Id,
                    TenantName = tenant.Title,
                    Permission = permission.Permission,
                    IsOwnTenant = false,
                    ExpireTime = permission.ExpireTime
                });
            }
        }

        return result.OrderBy(t => t.IsOwnTenant ? 0 : 1).ThenBy(t => t.TenantName).ToList();
    }

    /// <summary>
    /// 验证用户对特定租户的权限 🔖
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="tenantId">租户ID</param>
    /// <param name="requiredPermission">所需权限</param>
    /// <returns></returns>
    [DisplayName("验证用户权限")]
    public virtual async Task<bool> HasPermission(long userId, long tenantId, CrossTenantPermissionEnum requiredPermission)
    {
        // 获取用户信息
        var user = await _userRep.GetByIdAsync(userId);
        if (user == null) return false;

        // 超级管理员有所有权限
        if (user.AccountType == AccountTypeEnum.SuperAdmin) return true;

        // 用户对自己的租户有完全权限
        if (user.TenantId == tenantId) return true;

        // 检查跨租户权限
        var crossTenantPermissions = await GetValidCrossTenantPermissions(userId);
        var permission = crossTenantPermissions.FirstOrDefault(p => p.TargetTenantId == tenantId);
        
        return permission?.HasPermission(requiredPermission) ?? false;
    }

    /// <summary>
    /// 获取用户有效的跨租户权限列表
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns></returns>
    [NonAction]
    public virtual async Task<List<SysUserCrossTenant>> GetValidCrossTenantPermissions(long userId)
    {
        // 先尝试从缓存获取
        var cacheKey = $"CrossTenantPermissions_{userId}";
        var cached = _sysCacheService.Get<List<SysUserCrossTenant>>(cacheKey);
        if (cached != null) return cached;

        // 从数据库获取有效权限
        var permissions = await _crossTenantRep.GetListAsync(ct => 
            ct.UserId == userId && 
            ct.IsActive == true &&
            (ct.ExpireTime == null || ct.ExpireTime > DateTime.Now));

        // 缓存30分钟
        _sysCacheService.Set(cacheKey, permissions, TimeSpan.FromMinutes(30));
        
        return permissions;
    }

    /// <summary>
    /// 获取用户可访问的租户ID列表
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns></returns>
    [NonAction]
    public virtual async Task<List<long>> GetAccessibleTenantIds(long userId)
    {
        var user = await _userRep.GetByIdAsync(userId);
        if (user == null) return new List<long>();

        var result = new List<long>();

        // 添加用户自己的租户
        if (user.TenantId.HasValue)
        {
            result.Add(user.TenantId.Value);
        }

        // 获取跨租户权限的租户ID
        var crossTenantPermissions = await GetValidCrossTenantPermissions(userId);
        result.AddRange(crossTenantPermissions.Select(p => p.TargetTenantId));

        return result.Distinct().ToList();
    }

    /// <summary>
    /// 清除用户跨租户权限缓存
    /// </summary>
    /// <param name="userId">用户ID</param>
    [NonAction]
    public virtual void ClearUserCrossTenantCache(long userId)
    {
        var cacheKey = $"CrossTenantPermissions_{userId}";
        _sysCacheService.Remove(cacheKey);
    }
}